﻿module ReturnCheck
open Ast

let rec private check_block (block : Ast.Block) = 
  let (Ast.Block(_, stmts, _)) = block
  if stmts |> Seq.exists (fun s -> match s with | Stmt.Return _ -> true | Stmt.Block block -> check_block block | _ -> false) then
    true
  else
    let may_ifthenelse = 
      stmts |> Seq.tryFind
        (fun stmt ->
          match stmt with
          | Stmt.If (_, _, Some _, _) -> 
            true
          | _ -> false)
    match may_ifthenelse with
    | Some (Stmt.If (_, stmt, Some else_stmt, _)) ->
      (check_stmt stmt) && (check_stmt else_stmt)
    | _ -> false

and private check_stmt stmt =
  match stmt with
  | Stmt.Block b ->
    check_block b
  | Stmt.Return _ ->
    true
  | Stmt.If (_, stmt, (Some else_stmt), _) ->
    (check_stmt stmt) && (check_stmt else_stmt)
  | _ -> false
  



let check_ret (prg : Ast.Program) = 
  for ClassDecl(_,_,fild_orMethods) in prg do
    for (f_or_m) in fild_orMethods do
      match f_or_m with
      | FieldOrMethodDecl.MethodDecl((ReturnType.Type _), _, _, block, _) -> 
        if check_block block |> not then
          System.Console.WriteLine"non void function must have return point"
          //failwith "non void function must have return point"
      | _ ->
        ()